package cn.lzx.generator;

import javafx.scene.control.TextArea;

import java.io.*;
import java.sql.*;

public class AutoGenerator {
    private boolean entityCheck;
    private boolean xmlCheck;
    private boolean modelCheck;
    private GlobalConfig globalConfig;
    private DataSourceConfig dataSourceConfig;
    private PackageConfig packageConfig;

    public boolean isEntityCheck() {
        return entityCheck;
    }

    public void setEntityCheck(boolean entityCheck) {
        this.entityCheck = entityCheck;
    }

    public boolean isXmlCheck() {
        return xmlCheck;
    }

    public void setXmlCheck(boolean xmlCheck) {
        this.xmlCheck = xmlCheck;
    }

    public boolean isModelCheck() {
        return modelCheck;
    }

    public void setModelCheck(boolean modelCheck) {
        this.modelCheck = modelCheck;
    }

    private GlobalConfig getGlobalConfig() {
        return globalConfig;
    }

    public void setGlobalConfig(GlobalConfig globalConfig) {
        this.globalConfig = globalConfig;
    }

    private DataSourceConfig getDataSourceConfig() {
        return dataSourceConfig;
    }

    public void setDataSourceConfig(DataSourceConfig dataSourceConfig) {
        this.dataSourceConfig = dataSourceConfig;
    }

    private PackageConfig getPackageConfig() {
        return packageConfig;
    }

    public void setPackageConfig(PackageConfig packageConfig) {
        this.packageConfig = packageConfig;
    }

    public String execute(TextArea actiontargetEntity) throws SQLException, IOException {
        try {
            Class.forName(getDataSourceConfig().getDriverName());//加载数据库驱动
        } catch (ClassNotFoundException e) {
            actiontargetEntity.setText("Exception====>" + e.getMessage());
            return "fail";
        }
        StringBuffer sbXml = new StringBuffer();
        StringBuffer sbEntity = new StringBuffer();
        StringBuffer sbModel = new StringBuffer();
        sbXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<!DOCTYPE hibernate-mapping PUBLIC \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"\n" +
                "        \"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd\">\n" +
                "<hibernate-mapping package=\"com.shinow.abc." + getPackageConfig().getBundleId() + ".domain" +
                ".model\">\n" +
                "    <class name=\"" + getPackageConfig().getFileName() + "\"" +
                "table=\"" + getDataSourceConfig().getTableName() + "\"\n" +
                "           dynamic-insert=\"true\" dynamic-update=\"true\">\n" +
                "        <id name=\"uuid\" type=\"string\" column=\"UUID\">\n" +
                "            <cn.lzx.generator class=\"uuid\"/>\n" +
                "        </id>\n");

        sbModel.append("Ext.define('Amili." + getPackageConfig().getBundleId() + ".model." + getPackageConfig().getFileName() +
                "', {\n");
        sbModel.append("    extend: 'Ext.data.Model',\n");
        sbModel.append("    idProperty: 'uuid',\n");
        Connection connection = getConn(actiontargetEntity);
        ResultSet rs = null;
        String jdbdStr = getDataSourceConfig().getDriverName().toLowerCase();
        if (jdbdStr.contains("mysql")) {
            rs = executeQuery(getStmt(connection), "select * from information_schema.columns where " +
                            "table_schema='financial' and  table_name='" + getDataSourceConfig().getTableName() + "'",
                    actiontargetEntity);
        } else if (jdbdStr.contains("oracle")) {
            rs = executeQuery(getStmt(connection), "select * from information_schema.columns where " +
                            "table_schema='financial' and  table_name='" + getDataSourceConfig().getTableName() + "'",
                    actiontargetEntity);
        }
        sbEntity.append("package com.shinow.abc." + getPackageConfig().getBundleId() + ".domain.model;\n\n")
                .append("public class " + getPackageConfig().getFileName() + " {\n");
        sbModel.append("    fields: [");
        if (!rs.next()) {
            actiontargetEntity.setText("请检查表名称！");
            closeRs(rs);
            closeConn(connection);
            return "fail";
        }
        while (rs.next()) {
            String name = rs.getString("COLUMN_NAME");
            sbXml.append("        <property name=\"")
                    .append(underlineToCamel(name))
                    .append("\" type=\"");
            sbEntity.append("    private ");
            sbModel.append("{\n");
            switch (rs.getString("DATA_TYPE")) {
                /***ORACLE***/
                case "NUMBER":
                    if (rs.getString("DATA_SCALE") != null && rs.getString("DATA_SCALE").equals("0")) {
                        sbXml.append("integer");
                        sbEntity.append("Integer");
                    } else {
                        sbXml.append("double");
                        sbEntity.append("Double");
                    }
                    sbModel.append("        name: '" + underlineToCamel(name) + "'\n")
                            .append("    },");
                    break;
                case "VARCHAR2":
                    sbXml.append("string");
                    sbEntity.append("String");
                    sbModel.append("        name: '" + underlineToCamel(name) + "'\n")
                            .append("    },");
                    break;
                case "DATE":
                    sbXml.append("timestamp");
                    sbEntity.append("Date");
                    sbModel.append("        name: '" + underlineToCamel(name) + "',\n")
                            .append("        type: 'date',\n")
                            .append("        dateFormat: 'Y-m-d H:i:s'\n")
                            .append("    },");
                    break;
                /***MYSQL***/
                case "int":
                    sbXml.append("integer");
                    sbEntity.append("Integer");
                    sbModel.append("        name: '" + underlineToCamel(name) + "'\n")
                            .append("    },");
                    break;
                case "varchar":
                    sbXml.append("string");
                    sbEntity.append("String");
                    sbModel.append("        name: '" + underlineToCamel(name) + "'\n")
                            .append("    },");
                    break;
                case "datetime":
                    sbXml.append("timestamp");
                    sbEntity.append("Date");
                    sbModel.append("        name: '" + underlineToCamel(name) + "',\n")
                            .append("        type: 'date',\n")
                            .append("        dateFormat: 'Y-m-d H:i:s'\n")
                            .append("    },");
                    break;
            }
            sbXml.append("\" column=\"")
                    .append(name)
                    .append("\"/>\n");
            sbEntity.append(" " + underlineToCamel(name))
                    .append(";\n");
        }
        sbXml.append("    </class>\n")
                .append("</hibernate-mapping>");
        sbEntity.append("}");

        sbModel.replace(0, sbModel.toString().length(), sbModel.toString().substring(0,
                sbModel.toString().length() - 1));

        sbModel.append("],\n")
                .append("    proxy: {\n")
                .append("        type: 'ajax',\n")
                .append("        extraParams: {\n")
                .append("            'source': 'amili'\n")
                .append("        },\n")
                .append("        api: {\n")
                .append("        read: './")
                .append(getPackageConfig().getFileName().toLowerCase())
                .append("/")
                .append(getPackageConfig().getFileName().toLowerCase()).append("s'\n")
                .append("             },\n")
                .append("        writer: {\n")
                .append("            writeAllFields: true\n")
                .append("        },\n")
                .append("        reader: {\n")
                .append("        type: 'json',\n")
                .append("        }\n")
                .append("    }\n")
                .append("});");

        StringBuffer msgB = new StringBuffer();
        if (isEntityCheck()) {
            msgB.append(writeFile(getGlobalConfig().getMainDir() + "\\java\\com\\shinow\\abc\\" + getPackageConfig().getBundleId() + "\\domain\\model\\" + getPackageConfig().getFileName() + ".java",
                    sbEntity.toString(),
                    !getGlobalConfig().getFileOverride(), actiontargetEntity));
        }
        if (isXmlCheck()) {
            msgB.append(writeFile(getGlobalConfig().getMainDir() + "\\resources\\com\\shinow\\abc\\" + getPackageConfig().getBundleId() + "\\domain\\model\\" + getPackageConfig().getFileName() +
                            ".hbm.xml",
                    sbXml.toString(),
                    !getGlobalConfig().getFileOverride(), actiontargetEntity));
            this.writeSessionFactoryXml("mysql", actiontargetEntity);
            this.writeSessionFactoryXml("oracle", actiontargetEntity);
            this.writeSessionFactoryXml("sqlserver", actiontargetEntity);
            this.writeSessionFactoryXml("test.mysql", actiontargetEntity);
            this.writeSessionFactoryXml("test.oracle", actiontargetEntity);
        }
        if (isModelCheck()) {
            msgB.append(writeFile(getGlobalConfig().getMainDir() + "\\resources\\public\\" + getPackageConfig().getBundleId() + "\\model\\" + getPackageConfig().getFileName() + ".js",
                    sbModel.toString(),
                    !getGlobalConfig().getFileOverride(), actiontargetEntity));
        }

        if (!isEntityCheck() && !isXmlCheck() && !isModelCheck()) {
            actiontargetEntity.setText("请至少选择一项！");
            return "fail";
        }


        closeConn(connection);
        actiontargetEntity.setText(msgB.toString() + "请重启软件！");
        return "success";

    }

    private Connection getConn(TextArea actiontargetEntity) {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(getDataSourceConfig().getUrl(), getDataSourceConfig().getUsername(),
                    getDataSourceConfig().getPassword());
        } catch (SQLException e) {
            actiontargetEntity.setText(e.getMessage());
        }
        return conn;
    }

    private static Statement getStmt(Connection conn) {
        Statement stmt = null;
        try {
            stmt = conn.createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return stmt;
    }

    private static ResultSet executeQuery(Statement stmt, String sql, TextArea actiontargetEntity) {
        ResultSet rs = null;
        try {
            rs = stmt.executeQuery(sql);
        } catch (SQLException e) {
            actiontargetEntity.setText(e.getMessage());
        }
        return rs;
    }

    //关闭结果集
    private static void closeRs(ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
                rs = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //关闭执行方法
    private static void closeStmt(Statement stmt) {
        try {
            if (stmt != null) {
                stmt.close();
                stmt = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    //关闭连接
    private static void closeConn(Connection conn) {
        try {
            if (conn != null) {
                conn.close();
                conn = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void writeSessionFactoryXml(String dataBaseType, TextArea actiontargetEntity) {
        String d =
                readFile(getGlobalConfig().getMainDir() + "\\resources\\hibernate." + getPackageConfig().getSessionFactoryID() +
                                "." + dataBaseType + ".cfg.xml",
                        "utf8");
        if (!d.contains("<mapping resource=\"com/shinow/abc/" + getPackageConfig().getBundleId() + "/domain/model" +
                "/" + getPackageConfig().getFileName() + ".hbm.xml\"/>")) {

            writeFile(getGlobalConfig().getMainDir() + "\\resources\\hibernate." + getPackageConfig().getSessionFactoryID() +
                    "." + dataBaseType + ".cfg.xml", d.replace("</session-factory>",
                    "    <mapping resource=\"com/shinow/abc/" + getPackageConfig().getBundleId() + "/domain" +
                            "/model/" + getPackageConfig().getFileName() + ".hbm.xml\"/>\n" +
                            "    </session-factory>"), false, actiontargetEntity);
        }
    }

    /**
     * 读文件
     *
     * @param filename 文件名（带路径）
     * @param chartset 编码
     * @return 文件内容
     */
    public static String readFile(String filename, String chartset) {
        StringBuffer sb = new StringBuffer();
        try {
            FileInputStream fis = new FileInputStream(filename);
            InputStreamReader isr = new InputStreamReader(fis, chartset);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while ((line = br.readLine()) != null) {
                // 一次读入一行数据
                sb.append(line + "\r\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 写文件
     *
     * @param filename 文件名（带路径）
     * @param content  内容
     * @param append   是否追加
     * @throws IOException
     */
    public String writeFile(String filename, String content, Boolean append, TextArea actiontargetEntity) {
        File file = new File(filename);
        try {
            System.out.println("存在");
            if (!file.exists()) {
                System.out.println("不存在");
                (new File(filename.substring(0, filename.lastIndexOf("\\")))).mkdirs();
                file.createNewFile();
            }
            //写入文件
            FileOutputStream fos = new FileOutputStream(file, append);
            OutputStreamWriter out = new OutputStreamWriter(fos, "utf-8");
            BufferedWriter bw = new BufferedWriter(out);
            bw.write(content);
            bw.write("\r\n");
            bw.flush();
        } catch (IOException e) {
            System.out.println(e.getMessage());
            actiontargetEntity.setText(e.getMessage());
        }
        return filename + "成功\n";
    }

    /**
     * 下划线 转 驼峰
     *
     * @param param
     * @return
     */
    private static String underlineToCamel(String param) {
        char UNDERLINE = '_';
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = Character.toLowerCase(param.charAt(i));
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}
